package shun.vm;


import shun.vm.instructions.*;

/**
 * Created by chen on 14-5-18.
 */
public class VM {

    private byte[] mCodes;
    private int mPc;
    private int[] mRegisters;

    public VM() {
        mRegisters = new int[256];
    }

    public void loadCode(byte[] codes) {
        mCodes = codes;
    }

    public void execute() {
        if (mCodes == null || mCodes.length == 0) {
            return;
        }

        boolean hasError = false;
        while (hasNext()) {
            Instruction i = next();
            if (i == null) {
                System.out.printf("The opcode %02x at %d is unrecognizable", mCodes[mPc], mPc);
                hasError = true;
                break;
            }
            i.execute();
            System.out.println("executed " + mPc + ": " + i);
            System.out.println("v0=" + mRegisters[0] + ", v1=" + mRegisters[1]);
            mPc += i.length();
        }
        if (hasError) {
            System.out.println("The VM exit unexceptionably");
        }
    }

    private boolean hasNext() {
        return mPc < mCodes.length;
    }

    private Instruction next() {

        byte code = mCodes[mPc];
        Instruction i = null;
        switch (code) {
            case Instruction.add:
                i = new add(this);
                break;
            case Instruction.sub:
                i = new sub(this);
                break;
            case Instruction.mul:
                i = new mul(this);
                break;
            case Instruction.div:
                i = new div(this);
                break;
            case Instruction.mod:
                i = new mod(this);
                break;
            case Instruction.mov:
                i = new mov(this);
                break;
        }

        if (i != null) {
            i.parse(mCodes, mPc);
        }
        return i;
    }

    public int[] getRegisters() {
        return mRegisters;
    }
}
